--施法技能
--                                 施法
--                    ----------------------------
--                    |                          |
-- 技能起手         开始引导   间隔触发         引导结束           技能结束
--   |                |      | | |               |               |
--   -------------------------------------------------------------
--         前摇阶段        引导持续阶段                    后摇阶段
---@class TBS.SkillBase
---@field New fun():TBS.SkillBase
local SkillBase = TBS.CreateClass("SkillBase")
--技能创建
function SkillBase:OnCreate(skillId)
    self.uniqueId = 0
    self.casterId = 0
    self.skillId = skillId
    self.skillTypeFlag = 0  --类型标记位
    self.stage = TBS.Config.SkillStage.none --阶段
    self.maxTime = 0    --技能持续时间
    self.curTime = 0    --技能计时
    ---@type TBS.SkillNodeBase[]
    self.nodeList = {}
    --cd
    self.initialCD = 0      --初始cd
    self.maxCd = 0
    self.curCd = 0
    --引导
    self.isInChannel = false    --引导中
    self.channelInterval = 0  --引导触发间隔
    self.channelTime = 0      --引导阶段总时长
    self.channelCurTime = 0
    self.channelCount = 0       --引导次数
    --spell 时间点
    self.castTime = 0
    self.callbackList = {}
    ---@type BaseContext
    self.context = {}
end
function SkillBase:OnDestroy()
    self.callbackList = {}
end
function SkillBase:Update(dt)
    if self:IsSkillEnd() then return end
    self.curTime = self.curTime + dt

    local STAGE = TBS.Config.SkillStage
    if self.curTime >= self.castTime and self.stage < STAGE.spell then
        self:OnSkillSpell()
    end
    if self.isInChannel then
        self.channelCurTime = self.channelCurTime + dt
        if self.channelCurTime >= self.channelTime then
            self:OnChannelFinish()
        elseif self.channelCurTime >= (self.channelCount + 1) * self.channelInterval then
            self.channelCount = self.channelCount + 1
            self:OnChannelThink()
        end
    end
    for k,v in pairs(self.nodeList) do
        v:Update(dt)
    end
    if self.maxTime > 0 and self.curTime >= self.maxTime then
        self:OnSkillEnd()
        return
    end
end
function SkillBase:AddNode(node)
    table.insert(self.nodeList,node)
end

function SkillBase:IsSkillEnd()
    return self.stage == TBS.Config.SkillStage.skillEnd
end
function SkillBase:UpdateCoolDown(dt)
    if self.curCd <= 0 then return end
    self.curCd = self.curCd - dt
    if self.curCd <= 0 then
        self.curCd = 0
        self:CoolDownFinished()
    end
end
---CD倒计时
function SkillBase:StartCoolDown(time)
    self.maxCd = time
    self.curCd = time
end

---引导开始计时
function SkillBase:StartChannel(totalTime,interval)
    self.channelCurTime = 0
    self.channelCount = 0
    self.channelTime = totalTime
    self.isInChannel = true
    self.channelInterval = interval
end
---CD倒计时结束
function SkillBase:CoolDownFinished()

end
function SkillBase:IsInCD()
    return self.curCd > 0
end
function SkillBase:DoSkill()
    if self:IsInCD() then
        return false
    end
    self:OnSkillInit()
    self:OnSkillStart()
    return true
end

---技能初始化
function SkillBase:OnSkillInit()
    self.stage = TBS.Config.SkillStage.init
    self.curTime = 0
    for k,v in pairs(self.nodeList) do
        v:Reset()
    end
end
---技能起手(前揺)
function SkillBase:OnSkillStart()
    self.stage = TBS.Config.SkillStage.start
end
---技能施法
function SkillBase:OnSkillSpell()
    self.stage = TBS.Config.SkillStage.spell
    self:DoSkillCallback(TBS.Config.SkillCallbackType.skillStart,self:CreateBaseContext())
end

---引导开始
function SkillBase:OnChannelStart()
    self.stage = TBS.Config.SkillStage.channelStart
end
---引导间隔触发
function SkillBase:OnChannelThink()
    self.stage = TBS.Config.SkillStage.channelIng
end
---引导结束
function SkillBase:OnChannelFinish()
    self.stage = TBS.Config.SkillStage.channelFinished
end

---技能后摇
function SkillBase:OnSkillBackSwing()
    self.stage = TBS.Config.SkillStage.backSwing
end
---技能结束
function SkillBase:OnSkillEnd()
    self.stage = TBS.Config.SkillStage.skillEnd
    self:DoSkillCallback(TBS.Config.SkillCallbackType.skillEnd,self:CreateBaseContext())
end
---激活类技能 打开
function SkillBase:OnSkillActivate()

end
---激活类技能 关闭
function SkillBase:OnSkillDeactivate()

end
--region callback
function SkillBase:RegisterCallback(callbackType,tb,callback,autoRemove)
    local tbList = self.callbackList[callbackType]
    if not tbList then
        tbList = {}
        self.callbackList[callbackType] = tbList
    end
    for k,v in pairs(tbList) do
        if v.tb == tb and v.callback == callback then
            return
        end
    end
    local temp = TablePool.Get()
    temp.tb = tb
    temp.callback = callback
    temp.autoRemove = autoRemove
    table.insert(tbList,temp)
end
function SkillBase:UnRegisterCallback(callbackType,tb,callback)
    local tbList = self.callbackList[callbackType]
    if not tbList then return end
    for k,v in pairs(tbList) do
        if v.tb == tb and v.callback == callback then
            table.remove(tbList,k)
            TablePool.ReleaseDeeper(v,false)
            return
        end
    end
end
---@private
---@param context BaseContext
function SkillBase:DoSkillCallback(callbackType,context)
    local tbList = self.callbackList[callbackType]
    if not tbList then return end
    local tb = TablePool.Get()
    for k,v in pairs(tbList) do
        table.insert(tb,v)
    end
    for k,v in pairs(tb) do
        v.callback(v.tb,context)
        if v.autoRemove then
            self:UnRegisterCallback(callbackType,v.tb,v.callback)
        end
        if context and context.eventFinish then
            break
        end
    end
    TablePool.ReleaseDeeper(tb,false)
end

---@return HitContext
function SkillBase:CreateHitContext(targetId,hitPosX,hitPosY)
    ---@type HitContext
    local context = self.context
    table.clear(context)
    context.casterId = self.casterId
    context.skillId = self.skillId
    context.targetId = targetId
    context.eventFinish = false
    context.damage = 0
    context.damageType = 0
    context.posX = hitPosX
    context.posY = hitPosY
    return context
end
function SkillBase:CreateBaseContext()
    ---@type BaseContext
    local context = self.context
    table.clear(context)
    context.skillId = self.skillId
    context.casterId = self.casterId
    return context
end
--endregion callback